﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;

namespace Apex.Dapper
{
    /// <summary>
    /// Mapper执行器
    /// </summary>
    public class MapperExecutor
    {
        // 数据库连接对象
        private readonly IDbConnection dbConnection;

        // Sql脚本数据流
        private readonly Stream stream;

        /// <summary>
        /// 构造MapperExecutor对象
        /// </summary>
        /// <param name="dbConnection">数据库连接对象</param>
        /// <param name="stream">脚本数据流</param>
        public MapperExecutor(IDbConnection dbConnection, Stream stream)
        {
            this.dbConnection = dbConnection;
            this.stream = stream;
        }

        /// <summary>
        /// 查询执行器
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="method">方法名</param>
        /// <param name="parameter">参数</param>
        /// <returns>结果集</returns>
        public IEnumerable<T> ExcuteQuery<T>(string method, object parameter = null)
            => parameter == null ?
                dbConnection.Query<T>(LoadScript("dapper/select/" + method)) :
                dbConnection.Query<T>(LoadScript("dapper/select/" + method), parameter);

        /// <summary>
        /// 非查询执行器
        /// </summary>
        /// <param name="method">方法名</param>
        /// <param name="parameter">参数</param>
        /// <returns>更新数据条目数</returns>
        public long ExecuteNoQuery(string method, object parameter = null)
            => parameter == null ?
                dbConnection.Execute(LoadScript("dapper/other/" + method)) :
                dbConnection.Execute(LoadScript("dapper/other/" + method), parameter);

        /// <summary>
        /// 动态条件查询执行器
        ///     仅适用于单表查询或者视图查询
        ///     基础SQL脚本必须是完整可执行的SQL语句
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="method">方法名</param>
        /// <param name="parameter">参数</param>
        /// <returns>结果集</returns>
        public IEnumerable<T> ExecuteQueryDynamic<T>(string method, object parameter = null)
        {
            string script = LoadScript("dapper/select/" + method);
            if (parameter != null)
            {
                string condition = "";
                PropertyInfo[] properties = parameter.GetType().GetProperties();
                foreach (PropertyInfo property in properties)
                {
                    IEnumerable<string> types = new List<string>() { "String", "Guid", "DateTime" };
                    Type type = property.PropertyType;
                    string value = property.GetValue(parameter, null).ToString();
                    if (types.Contains(type.Name)) value = "'" + property.GetValue(parameter, null).ToString() + "'";
                    else value = property.GetValue(parameter, null).ToString();
                    condition += "and " + property.Name + "=" + value + " ";
                }  
                if (script.Contains("where") || script.Contains("Where") || script.Contains("WHERE")) script += condition;
                else script += " where " + condition.Substring(4, condition.Length - 4);
            }
            return dbConnection.Query<T>(script);
        }

        /// <summary>
        /// 加载Mapper执行脚本
        /// </summary>
        /// <param name="method">方法名</param>
        /// <returns>执行脚本</returns>
        /// <exception cref="Exception">找不到方法</exception>
        private string LoadScript(string method)
        {
            string script = "";
            if (stream != null)
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(new StreamReader(stream).ReadToEnd());
                XmlNode rootNode = xmlDoc.SelectSingleNode(method);
                if (rootNode == null) throw new Exception("查找不到方法：" + method);
                foreach (XmlNode node in rootNode.ChildNodes) script = node.InnerText;
            }
            return script;
        }
    }
}
